/* ======================================================================================== *\

		FILE:				Profiling.cpp
		AUTHOR:				Jack Hoxley

		DESCRIPTION:		Provides the definitions for utility functions used when
							profiling the main application.

		CHANGE:				5th May 2007
								Basic public interface implemented.
							8th May 2007
								Implemented basic ID3D10InfoQueue tracing
							14th May 2007
								Removed ID3D10InfoQueue tracing due to performance concerns

\* ======================================================================================== */

// Include Standard Headers
// ------------------------
#include "DXUT.h"
#include <time.h>

// Include project headers
// -----------------------
#include "Profiling.h"
#include "Utils.h"


namespace D3DUtils
{
	// =======================================================================================
	// P R I V A T E   V A R I A B L E S
	// =======================================================================================
	ID3D10InfoQueue*		g_pInfoQueue						= NULL;


	// =======================================================================================
	// P U B L I C   F U N C T I O N S
	// =======================================================================================

	ScopeProfiler::ScopeProfiler( WCHAR* Name, int Line )
	{
		// Create a PIXfW marker
		WCHAR wc[ MAX_PATH ];
		StringCchPrintf( wc, MAX_PATH, L"%s @ Line %d.\0", Name, Line );
		D3DPERF_BeginEvent( D3DCOLOR_XRGB( rand() % 255, rand() % 255, rand() % 255 ), wc );
		srand( static_cast< unsigned >( time( NULL ) ) );

		// If we've got an ID3D10InfoQueue object available then
		// Push a new message:
		if( NULL != g_pInfoQueue )
		{
			/*
			int len = WideCharToMultiByte( CP_ACP, WC_DEFAULTCHAR, Name, -1, NULL, 0, NULL, NULL );
			char* cName = new char[ len ];
			WideCharToMultiByte( CP_ACP, WC_DEFAULTCHAR, Name, -1, cName, len, NULL, NULL );
			
			char c[ MAX_PATH ];
			StringCchPrintfA( c, MAX_PATH, "ENTER: %s @ Line %d.\0", cName, Line );

			g_pInfoQueue->AddApplicationMessage( D3D10_MESSAGE_SEVERITY_INFO, c );

			SAFE_DELETE_ARRAY( cName );
			*/
		}
	}



	ScopeProfiler::~ScopeProfiler( )
	{
		// Make sure the PIXfW marker has a matching end event
		D3DPERF_EndEvent( );

		// If we've got an ID3D10InfoQueue interface then make sure
		// we mark it as finished; but we also need to track the amount
		// of time this particular block has taken.
		if( NULL != g_pInfoQueue )
		{
			//g_pInfoQueue->AddApplicationMessage( D3D10_MESSAGE_SEVERITY_INFO, "LEAVING: ???" );
		}
	}


	
	HRESULT InitializeTracing( )
	{
		// Try to obtain an info queue interface:
		ID3D10Device *pDev = DXUTGetD3D10Device( );

		HRESULT hr = pDev->QueryInterface( __uuidof( ID3D10InfoQueue ), reinterpret_cast< void** >( &g_pInfoQueue ) );

		if( FAILED( hr ) )
		{
			ERR_OUT( L"Failed to obtain an ID3D10InfoQueue interface!" );
		}
		else
		{
			// Configure the queue
			INFO_OUT( L"Successfully obtained an ID3D10InfoQueue interface." );
		}

		return hr;
	}



	HRESULT TerminateTracing( )
	{
		// Auto-generate a file name
		// to use:
		WCHAR *wcName = L"dummy_string.txt";

		// Call the proper implementation
		// of this method:
		TerminateTracing( wcName );

		return S_OK;
	}



	HRESULT TerminateTracing( WCHAR *TraceLogName )
	{
		// Write out the log file to disk

		// Make sure the memory is
		// safely released to avoid 
		// memory leaks
		SAFE_RELEASE( g_pInfoQueue );

		return S_OK;
	}



	HRESULT RequestGPUSynchronization( )
	{
		HRESULT				hr			= E_FAIL;
		ID3D10Debug*		pDebug		= NULL;
		ID3D10Device*		pDevice		= DXUTGetD3D10Device();
		
		if( NULL != pDevice )
		{
			hr = pDevice->QueryInterface( __uuidof( ID3D10Debug ), reinterpret_cast< void** >( &pDebug ) );

			if( NULL != pDebug )
			{
				hr = pDebug->SetFeatureMask( D3D10_DEBUG_FEATURE_FINISH_PER_RENDER_OP );
			}
		}

		SAFE_RELEASE( pDebug );

		if( SUCCEEDED( hr ) )
		{
			INFO_OUT( L"Function returns SUCCESS" );
		}
		else
		{
			WARN_OUT( L"Function FAILS" );
		}

		return hr;
	}
}